# -*- coding: utf-8 -*-

"""
  @author: tangliqi
  @date: 2022/9/18 23:13
  @python version: 3.6 
  
  ---------------------------------------
  @desc: python设计模式实现 => 动态代理模式.py
"""


# 静态代理的缺点在于: 当真实类的方法越来越多的时候，这样构建的代理类的代码量是非常大的，所以就引进动态代理
# 动态代理最大的好处就是：能够根据传入的真实类动态识别和拦截调用的方法，对方法进行附加操作，不需要每个方法写对应的代理方法


# ============================  真实类  ============================
class RentHouse:
    user = "aa"

    def rent_house(self, a):
        print(a)
        print("我是房东，要出租房子")

    def check_house(self):
        print("检查一下房子")


# ============================  公共代理类(通过 getattr 实现)  ============================
# 重新实现__getattr__方法即可拦截访问
class DynamicProxy:
    def __init__(self, target: RentHouse):
        self.__dict__["target"] = target  # 传入的真实类

    def __getattr__(self, attr):
        ret = None  # 可以找不到返回None，也可以抛出异常。
        # if hasattr(self.target, attr):
        print("检查房子")
        ret = getattr(self.target, attr)
        print("收取中介费")
        return ret

    def test(self):
        pass

    def __setattr__(self, name, value):
        return setattr(self.target, name, value)


# ============================  公共代理类(通过 getattribute 实现)  ============================
class DynamicProxy1:

    def __init__(self, target):
        self.target = target  # 传入的真实类

    def __getattr__(self, item):
        return getattr(self.target, item)

    def __setattr__(self, name, value):
        return setattr(self.target, name, value)

    def __getattribute__(self, name):
        target = object.__getattribute__(self, "target")
        attr = object.__getattribute__(target, name)

        def newAttr(*args, **kwargs):  # 包装
            print("前操作")
            res = attr(*args, **kwargs)
            print("后操作")
            return res

        return newAttr


if __name__ == "__main__":
    # 通过 __getattr__ 方法实现
    target = RentHouse()

    proxy = DynamicProxy(target)
    proxy.rent_house(666)
    print(proxy.user)
    # proxy.rent_house2(666)

    # proxy = DynamicProxy1(target)
    # proxy.rent_house(666)
    # proxy.rent_house2(666)
